/*---------------------------------------------------------------------
 * File name: hal_pwm.cpp
 *
 * Copyright (c) <2020-2022>, <ChenLong>
 *
 * All rights reserved.
 *
 * Author: ChenLong
 * Email: worldlong@foxmail.com
 *--------------------------------------------------------------------*/
#include "stm32f30x_gpio.h"
#include "stm32f30x_tim.h"
#include "stm32f30x_rcc.h"
#include "hal_pwm.h"
#if defined(USING_RT_THREAD)
#include <rtthread.h>
#endif
/*
*/
bool HAL_PWM::init(hal::Timer *timer0, uint32_t cfg0)
{
  timer = timer0;
  cfg = cfg0;
  return config(cfg);
}
/*
*/
bool HAL_PWM::config(uint32_t cfg0)
{
  cfg &= ~PWM_CFG_MASK;
  cfg |= cfg0 & PWM_CFG_MASK;
  	
  /* OC config */
  TIM_OCInitTypeDef  TIM_OCInitStructure;
  
  uint32_t tmp = PWM_CFG_EXTRACT(cfg, MODE);
  if(tmp == PWM_MODE(1)) {
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
  } else if(tmp == PWM_MODE(2)) {
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;
  } else {
    return false;
  }
  
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
  TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
  
  tmp = PWM_CFG_EXTRACT(cfg, OCP);
  if(tmp == PWM_OCP(HIGH)) { 
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;
  } else { 
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
  }
  
  tmp = PWM_CFG_EXTRACT(cfg, OCIDS);
  if(tmp == PWM_OCIDS(SET)) { 
    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset;
  } else {
    TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;
    TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Set;
  }
  
  TIM_OCInitStructure.TIM_Pulse = 0;

  TIM_TypeDef *TIMx = (TIM_TypeDef *)timer->port;
  
  tmp = PWM_CFG_EXTRACT(cfg, CH);
  if(tmp & PWM_CH(1)) { 
    TIM_OC1Init(TIMx, &TIM_OCInitStructure);
    TIM_OC1PreloadConfig(TIMx,TIM_OCPreload_Enable);
  }
  if(tmp & PWM_CH(2)) { 
    TIM_OC2Init(TIMx, &TIM_OCInitStructure);
    TIM_OC2PreloadConfig(TIMx,TIM_OCPreload_Enable);
  }
  if(tmp & PWM_CH(3)) { 
    TIM_OC3Init(TIMx, &TIM_OCInitStructure);
    TIM_OC3PreloadConfig(TIMx,TIM_OCPreload_Enable);
  }
  if(tmp & PWM_CH(4)) { 
    TIM_OC4Init(TIMx, &TIM_OCInitStructure);
    TIM_OC4PreloadConfig(TIMx,TIM_OCPreload_Enable);
  }
  
  TIM_Cmd(TIMx, ENABLE);
  if(TIMx == TIM1 || TIMx == TIM8 || 
     TIMx == TIM15 || TIMx == TIM16 || 
     TIMx == TIM17 || TIMx == TIM20) {
    TIM_CtrlPWMOutputs(TIMx, ENABLE);
  }
  
  return true;
}
/*
*/
void HAL_PWM::set_percent(int index, float percent0)
{
  TIM_TypeDef *TIMx = (TIM_TypeDef *)timer->port;
  percent[index - 1] = percent0;
  TIMx->CCR1 = (uint16_t)(timer->period * percent[0]);
  TIMx->CCR2 = (uint16_t)(timer->period * percent[1]);
  TIMx->CCR3 = (uint16_t)(timer->period * percent[2]);
  TIMx->CCR4 = (uint16_t)(timer->period * percent[3]);
}
/*
*/
void HAL_PWM::set_percent(float *percent0)
{
  TIM_TypeDef *TIMx = (TIM_TypeDef *)timer->port;
  memcpy(percent, percent0, sizeof(float)*4);

  TIMx->CCR1 = (uint16_t)(timer->period * percent[0]);
  TIMx->CCR2 = (uint16_t)(timer->period * percent[1]);
  TIMx->CCR3 = (uint16_t)(timer->period * percent[2]);
  TIMx->CCR4 = (uint16_t)(timer->period * percent[3]);
}
/*
*/
void HAL_PWM::set_percent(int index, uint32_t percent0)
{
  TIM_TypeDef *TIMx = (TIM_TypeDef *)timer->port;
  percent1000[index - 1] = percent0;
  TIMx->CCR1 = (uint16_t)(timer->period * percent1000[0] / 1000);
  TIMx->CCR2 = (uint16_t)(timer->period * percent1000[1] / 1000);
  TIMx->CCR3 = (uint16_t)(timer->period * percent1000[2] / 1000);
  TIMx->CCR4 = (uint16_t)(timer->period * percent1000[3] / 1000);
}
/*
*/
void HAL_PWM::set_percent(uint32_t *percent0)
{
  TIM_TypeDef *TIMx = (TIM_TypeDef *)timer->port;
  memcpy(percent1000, percent0, sizeof(uint32_t)*4);

  TIMx->CCR1 = (uint16_t)(timer->period * percent1000[0] / 1000);
  TIMx->CCR2 = (uint16_t)(timer->period * percent1000[1] / 1000);
  TIMx->CCR3 = (uint16_t)(timer->period * percent1000[2] / 1000);
  TIMx->CCR4 = (uint16_t)(timer->period * percent1000[3] / 1000);
}
